package MP.lexicalanalysis;
import java.io.*;

public class Scanner {
    private static final char EOF = '\u0000';
    ErrorReporter reporter;
    SourcePosition position;
	ScannerBuffer buff;
	int state = 0;
	
    public Scanner() {
    	position = new SourcePosition();
    }

    public Scanner(String fileName, ErrorReporter er) {
    	reporter = er;
    	position = new SourcePosition(); 	
        buff = new ScannerBuffer(fileName);
    }
  
    private char nextChar() 
    {
    	position.charFinish++;
    	return buff.nextChar();
    }

    public Token nextToken()
    {
    	Token result = null;
    	state = 0;
    	char c = ' ';
    	String lexeme = null;
    	while (true)
    	{
    		switch (state)
    		{
    		case 0:
                c = nextChar();
                if (c == ' ' || c == '\t' || c == '\r'|| c == '\n')
                 {
                    if (c == '\n') 
                    { 
	                    position.newLine();	                    
	          	    }
	          	    else
	          	    if (c == '\t')
	          	    {
	          	    	position.charStart += 8; 
	          	    	position.charFinish += 7;
	          	    }
	                else
	                {	                	
	                	position.charStart++;//charFinish has already increased by 1
	                }
	             } 
	             //Xu ly < , <= , <>
	             else 
	             if (c == '<') 
	             	{
	               		state = 1;
                 	}
                 // Xu ly > , >=
        		  else
        		  if(c == '>')
        		  	{
        		  		state = 2;
        		 	}
                 //Xu ly : , :=
                 else
                 if(c == ':')
                 {
                 	state = 3;
                 }
                 //Xu ly String
                 else
                 if(c == '\'')
                 {
                 	state = 5;
                 }
                 //Xu lt op *
                 else                 	
                 	if(c == '*')
                 	{
                 		result = new Token(Token.MULOP,"*",position);
        				position.charFinish++;//go to next position
        				position.endToken();
	               	 	return result;
                 	}
                 	//Xuly op / & comment
                 	else
                 	if(c == '/')
                 	{
                 		state = 4;
                 	}
                 	//Xu ly op +*/
                 	else 
                 	if (c == '+') 
                  	{
                		result = new Token(Token.ADDOP,"+",position);
        				position.charFinish++;//go to next position
        				position.endToken();
	               	 return result;
        		  	}        		  	
        		  	//Xu ly op -
        		  	else
            		  	if(c == '-')
        		  		{
                			result = new Token(Token.ADDOP,"-",position);
        					position.charFinish++;//go to next position
        					position.endToken();
	               			return result;
        		  		}        		  		
        		  		//Xu ly =
        		  		else
        		  		if(c == '=')
        		  		{
        		  			result = new Token(Token.EQOP,"=",position);
        					position.charFinish++;//go to next position
        					position.endToken();
	               	 		return result;
        		  		}        		  	 	
	               		//Xu ly ( 
	               		else	               		
	               		if(c == '(')
	               		{
	               			result = new Token(Token.LEFTPAR,"(",position);
        					position.charFinish++;//go to next position
        					position.endToken();
	               	 		return result;
	               		}
	               		//Xu ly )
	               		else
	               		if(c == ')')
	               		{
	               			result = new Token(Token.RIGHTPAR,")",position);
        					position.charFinish++;//go to next position
        					position.endToken();
	               	 		return result;
	               		}
	               		//Xu ly [
	               		else
	               		if(c =='[')
	               		{
	               			result = new Token(Token.LEFTSQURBRK,"[",position);
        					position.charFinish++;//go to next position
        					position.endToken();
	               	 		return result;
	               		}
	               		//Xu ly ]
	               		else
	               		if(c == ']')
	               		{
	               			result = new Token(Token.RIGHTSQURBRK,"]",position);
        					position.charFinish++;//go to next position
        					position.endToken();
	               	 		return result;
	               		}
	               		//Xu ly ,
	               		else
	               		if(c == ',')
	               		{
	               			result = new Token(Token.COMMA,",",position);
        					position.charFinish++;//go to next position
        					position.endToken();
	               	 		return result;
	               		} 
	               		//Xuly ;
	               		else
	               		if(c == ';')
	               		{
	               			result = new Token(Token.SEMICOLON,";",position);
        					position.charFinish++;//go to next position
        					position.endToken();
	               	 		return result;
	               		}
	               		//Xu ly lien quan Dot
	               		else
	               		if(c == '.')
	               		{
	               			state = 8;
	               		}
	               		//Xu ly so
	               		else
        		  		if(Character.isDigit(c))
        		  		{
        		  			state = 6;
        		  		}
	               		//Xu ly id
        		   		else 
        		   		if (Character.isLetter(c)|c=='_') 
        		   		{
        		    		state = 7;
	               		}
	               		//Ket thuc file
	               		else
	               		if (c == EOF) 
	               			{
				    			return new Token(Token.EOF,"$",position);
				   			} 
				   		else
				   			{
                			result = new Token(Token.ERROR,String.valueOf(c),position);
        					position.charFinish++;//go to next position
        					position.endToken();
	                		return result;
				   			}
					
                break;
    		case 1:
    			c = nextChar();
    			if (c == '=')
    			{
    				result = new Token(Token.RELOP,"<=",position);
        			position.charFinish++;//go to next position
    			}
    			else if (c == '>')
    			{
    				result = new Token(Token.RELOP,"<>",position);
        			position.charFinish++;//go to next position
    			}
    				else
    			{
                	buff.goBackOneCharacter();//read the "current read character" one more time
    				result = new Token(Token.RELOP,"<",new SourcePosition
    				(position.charStart,position.charFinish-1,position.lineStart,position.lineFinish));  				
        		}
    			position.endToken();
    			return result;
    		case 2:
    			//Xu ly > , >=
    			c = nextChar();
    			if(c == '=')
    			{
    				result = new Token(Token.RELOP,">=",position);
    				position.charFinish++;
    			}
    			else
    			{
    				buff.goBackOneCharacter();
    				result = new Token(Token.RELOP,">",new SourcePosition
    				(position.charStart,position.charFinish-1,position.lineStart,position.lineFinish));
    			}  
    			position.endToken();
    			return result;
    		case 3:
    			//Xu ly : , :=
    			c = nextChar();
    			if(c == '=')
    			{
    				result = new Token(Token.ASSIGNOP,":=",position);
    				position.charFinish++;
    			}
    			else
    			{
    				buff.goBackOneCharacter();
    				result = new Token(Token.COLON,":",new SourcePosition
    				(position.charStart,position.charFinish-1,position.lineStart,position.lineFinish));
    			}
    			position.endToken();
    			return result;
    			
    			//-------------con chua xu ly xong chi duoc 1 phan---
    			case 4: 
    			// Xu ly comment & MULOP & //
    			c = nextChar();    			
    			boolean flagComment = true;
    			if(c != '*' && c != '/')
    			{    				
    	 			buff.goBackOneCharacter();
    	 			position.charFinish--;
    	 			result = new Token(Token.MULOP,"/",position);
        			position.charFinish++;//go to next position
        			position.endToken();
	               	return result;
    			}
    			else
    			if(c == '/')
    			{
    				//c = nextChar();
    				
    				
    				while(true)
    				{
    					c = nextChar();    					
    				
    					if(c == '\n')
    					{
    						position.newLine();
    						state = 0;
    						break;    						
    					}
    					else
    					if(c == EOF)
    					{
    						buff.goBackOneCharacter();
    						position.charStart = position.charFinish;
    						position.charFinish--;
    						state =0;
    						break;
    					}    					   					
    				
    				}    				
    			}
    	 		else
    	 		{ 			
	             	int stateComment = 0;
    				c = nextChar();    				
    				boolean flagSpecial = false;   	
    				while(flagComment)
    				{    					
    				switch(stateComment)
    				{
    				case 0:
    				while(true)
    				{       					
    					if(c == '\n')
    					{
    						position.charFinish = 1;
    						position.lineFinish++;
    						flagSpecial = true;
    					}
    					else
    					if(c == '\t')
    					{
    						position.charFinish += 7;
    					}    					
    					else    					    					 						
    					if(c == '*')
    					{
    						flagSpecial = false;
    						stateComment = 1;    						
    						break;
    					}else 				
    					if(c == EOF)
    					{ 
    						if(flagSpecial)
    						{    						
    							position.charFinish--;
    						}    							   						
    						result = new Token(Token.ERROR,"Unterminated comment",
                				new SourcePosition(position.charStart,position.charFinish-1,
                				position.lineStart,position.lineFinish));
                			position.lineStart = position.lineFinish;
                			                			
            				buff.goBackOneCharacter();//read the "current read character" one more time
                			position.endToken();
                			return result;
    					}
    					c = nextChar();
    				}
    				break;
    				case 1:
    					c = nextChar();
    					while(c == '*')
    					{
    						c = nextChar();
    					}    		    					
    					if(c == '/')
    					{
    						position.charStart = position.charFinish;
    						position.charStart++;
    						position.lineStart = position.lineFinish;
    						flagComment = false;
    						state = 0;
    						break;
    					}
    					else
    					if(c == EOF)
    					{
    						if(flagSpecial)
    						{    						
    							position.charFinish--;
    						}    						
    						result = new Token(Token.ERROR,"Unterminated comment",
                				new SourcePosition(position.charStart,position.charFinish-1,
                				position.lineStart,position.lineFinish));                			
            				buff.goBackOneCharacter();//read the "current read character" one more time
                			position.endToken();
                			return result;
    					}
    					else
    					{
    						stateComment = 0;
    						c = nextChar();    						
    					}
    				}
    				}          	 	               	                	 
    	 		} 
    	 		break;
    			 //------------------------------------------
    			 //Xu ly String      			 
    			 case 5:
    	 		lexeme = "";    	 		    	 		
    	 		int initPos = 0;//ghi nhan vi tri bat duoc su kien \
    	 		int lastPos = 0;//gan gia tri la 7 neu gap \t con khong thi bang 0
    	 		int stateString = 0;    	 		
    	 		String illEscapeStr = "";
    	 		while(true)
    	 		{
    	 			switch(stateString)
    	 			{   	 			
    	 			case 0:
    	 			c = nextChar();
    				while(true)
    				{       					
    					if(c == '\'')
    					{
    						result = new Token(Token.STRINGLITERAL,lexeme,position);
    						position.charFinish++;
    						position.endToken();
    						return result;
    					}    					
    					else    					    					 						
    					if(c == '\\')
    					{
    						initPos = position.charFinish;
    						illEscapeStr += c;
    						lexeme += c;
    						stateString = 1;     						   						
    						break;
    					}else 				
    					if(c == EOF || c == '\n')
    					{   
    						//CharFinish giam 1 vi
    						//neu c = EOF thi phai bo ky tu nay lai dong thoi charFinish giam 1
    						//Neu c = \n thi doc vao 2 ky tu \r va \n do do giam 1 la bo ky tu \n					
                			result = new Token(Token.ERROR,"Unterminated string",
                				new SourcePosition(position.charStart,position.charFinish-1,
                				position.lineStart,position.lineFinish));
                			position.lineStart = position.lineFinish;                			                			
            				buff.goBackOneCharacter();//read the "current read character" one more time
                			position.endToken();
                			return result;        
    					}
    					else    					
    					if(c == '\t')
    						{
    							position.charFinish += 7;
    						}
    					lexeme += c;
    					c = nextChar();
    				}
    				break;
    				case 1:
    					c = nextChar();    					
    					if(c == 'b' || c == 'f' || c == 'r' || c == 'n' || c == 't'
    							|| c == '\'' || c == '\"' || c == '\\')
    					{
    						lexeme += c;
    						illEscapeStr = "";
    						stateString = 2;
    						break;
    					}
    					else
    					if(c == EOF || c == '\n')
    					{
    						if(illEscapeStr.equals("\\"))
    						{
    							System.out.println("Error:Illegal escape character "+
    							String.valueOf(illEscapeStr)+" "+"charStart="+String.valueOf(initPos)+" "+
    							"charFinish="+String.valueOf(initPos)+" "+"lineStart="
    							+String.valueOf(position.lineStart)+" "+"lineFinish="+String.valueOf(position.lineFinish));
    						illEscapeStr ="";	
    						}   					
                			result = new Token(Token.ERROR,"Unterminated string",
                				new SourcePosition(position.charStart,position.charFinish-1,
                				position.lineStart,position.lineFinish));
                			position.lineStart = position.lineFinish;                			                			
            				buff.goBackOneCharacter();//read the "current read character" one more time
                			position.endToken();
                			return result;
    					}    				
    					else
    					{
    						if(c == '\t')
    						{
    							lastPos += 8;
    						}
    						else
    						{
    							lastPos += 1;
    						}
    						illEscapeStr += c;
    						stateString = 3;
    						lexeme += c;    					;
    						System.out.println("Error:Illegal escape character "+
    							String.valueOf(illEscapeStr)+" "+"charStart="+String.valueOf(initPos)+" "+
    							"charFinish="+String.valueOf(initPos + 1)+" "+"lineStart="
    							+String.valueOf(position.lineStart)+" "+"lineFinish="+String.valueOf(position.lineFinish));
    						illEscapeStr ="";
    						position.charFinish = initPos + lastPos;
    						lastPos = 0; 
    						stateString = 0;
    						break;   						
    					}
    				case 2:    					
    				case 3:
    					c = nextChar();
    					if(c == EOF || c == '\n')
    					{    						
                			result = new Token(Token.ERROR,"Unterminated string",
                				new SourcePosition(position.charStart,position.charFinish-1,
                				position.lineStart,position.lineFinish));
                			position.lineStart = position.lineFinish;                			                			
            				buff.goBackOneCharacter();//read the "current read character" one more time
                			position.endToken();
                			return result;
    					}
    					else
    					if(c == '\'')
    					{
    						result = new Token(Token.STRINGLITERAL,lexeme,position);
    						position.charFinish++;
    						position.endToken();
    						return result;
    					}
    					else
    					if(c == '\\')
    					{
    						initPos = position.charFinish;
    						illEscapeStr += c;    						
    						stateString = 1;
    						lexeme += c;
    						break;
    					}
    					else
    					{
    						if(c == '\t')
    						{
    							position.charFinish += 7;
    						}
    						stateString = 0;
    						lexeme += c;
    						break;
    					}
    	 			}
    	 		}
    	 		//-------------------------------------------------------
    	 	//--------------------Xu ly so -----------------
    	 	case 6:
    	 		int stateReal = 0;
    	 		boolean flagReal = false;//Co bao dung la so thuc khong
    	 		char aheadReal;//Ky tu khi vao nhan chuoi
    	 		String tempReal = "";//Dung de luu lai khi vao nhan E & e
    	 		lexeme = "" + c;
    	 		int countReal = 0;//Dem so ky tu khi vao nhan e & E
    	 		while(true)
    	 		{
    	 			switch(stateReal)
    	 			{
    	 				case 0:
    	 					while(true)
    	 					{
    	 						c = nextChar();
    	 						if(c == '.')
    	 						{
    	 							lexeme += c;
    	 							flagReal = true;
    	 							stateReal = 1;
    	 							break;
    	 						}
    	 						else
    	 						if(c == 'e' || c == 'E')
    	 						{
    	 							tempReal += c;
    	 							countReal++;
    	 							buff.goBackOneCharacter();//Tral lui 1 ky tu
    	 							buff.goAheadOneCharacter();//Lay toi 1 ky tu
    	 							stateReal = 2;
    	 							break;
    	 						}
    	 						else
    	 						if(Character.isDigit(c))
    	 						{
    	 							lexeme += c;
    	 						}
    	 						else
    	 						{
    	 							result = new Token(Token.INTLITERAL,lexeme,
                						new SourcePosition(position.charStart,position.charFinish-1,
                						position.lineStart,position.lineFinish));                			
            						buff.goBackOneCharacter();//read the "current read character" one more time
                					position.endToken();
                					return result;
    	 						}    	 						    	 							
    	 					}
    	 					break;
    	 				case 1:
    	 					while(true)
    	 					{
    	 						c = nextChar();
    	 						if(c == 'e' || c == 'E')
    	 						{
    	 							tempReal += c;
    	 							countReal++;
    	 							buff.goBackOneCharacter();//Tra lui 1 ky tu
    	 							buff.goAheadOneCharacter();//Lay tiep 1 ky tu
    	 							stateReal = 2;
    	 							break;
    	 						}
    	 						else
    	 						if(Character.isDigit(c))
    	 						{
    	 							lexeme += c;
    	 						}
    	 						else
    	 						{
    	 							result = new Token(Token.REALLITERAL,lexeme,
                						new SourcePosition(position.charStart,position.charFinish-1,
                						position.lineStart,position.lineFinish));                			
            						buff.goBackOneCharacter();//read the "current read character" one more time
                					position.endToken();
                					return result;
    	 						}
    	 					}
    	 					break;
    	 				case 2:
    	 					aheadReal = buff.goAheadOneCharacter();
    	 					tempReal += aheadReal;
    	 					//countReal++;    	 					
    	 						if(Character.isDigit(aheadReal))
    	 						{    	 							
    	 							stateReal = 4;    	 							
    	 							position.charFinish += countReal;
    	 							lexeme += tempReal;
    	 							break; 
    	 						}
    	 						else
    	 						if(aheadReal == '+' || aheadReal == '-')
    	 						{
    	 							stateReal = 3;
    	 							break;
    	 						}
    	 						else
    	 						{
    	 							buff.goBackOneCharacter();
    	 							if(flagReal)
    	 							{
    	 							result = new Token(Token.REALLITERAL,lexeme,
                						new SourcePosition(position.charStart,position.charFinish-1,
                						position.lineStart,position.lineFinish));                			
            						buff.goBackOneCharacter();//read the "current read character" one more time
                					position.endToken();
                					return result;
    	 							}
    	 							result = new Token(Token.INTLITERAL,lexeme,
                						new SourcePosition(position.charStart,position.charFinish-1,
                						position.lineStart,position.lineFinish));                			
            						buff.goBackOneCharacter();//read the "current read character" one more time
                					position.endToken();
                					return result;
    	 						}
    	 				case 3:
    	 					aheadReal = buff.goAheadOneCharacter();
    	 					tempReal += aheadReal;
    	 					countReal++;
    	 					if(Character.isDigit(aheadReal))
    	 					{
    	 						stateReal = 4;    	 							
    	 						position.charFinish += countReal;
    	 						lexeme += tempReal;
    	 						break;
    	 					}
    	 					else
    	 					{
    	 						buff.goBackOneCharacter();
    	 						if(flagReal)
    	 						{
    	 							result = new Token(Token.REALLITERAL,lexeme,
                						new SourcePosition(position.charStart,position.charFinish-1,
                						position.lineStart,position.lineFinish));                			
            						buff.goBackOneCharacter();//read the "current read character" one more time
                					position.endToken();
                					return result;
    	 						}
    	 						result = new Token(Token.INTLITERAL,lexeme,
                					new SourcePosition(position.charStart,position.charFinish-1,
                					position.lineStart,position.lineFinish));                			
            					buff.goBackOneCharacter();//read the "current read character" one more time
                				position.endToken();
                				return result;
    	 					}    	 					
    	 				case 4:    	 					
    	 					while(true)
    	 					{
    	 						c = nextChar();
    	 						if(!Character.isDigit(c))
    	 						{
    	 							break;
    	 						}
    	 						else
    	 						{
    	 							lexeme += c;
    	 						}
    	 					}
    	 					result = new Token(Token.REALLITERAL,lexeme,
                				new SourcePosition(position.charStart,position.charFinish-1,
                				position.lineStart,position.lineFinish));                			
            				buff.goBackOneCharacter();//read the "current read character" one more time
                			position.endToken();
                			return result;    	 					
    	 			}
    	 		}    	 	
    	 		//------------------------------------------------	     			    			
            case 7:
            	lexeme = "";
                while (true)
                {
	                if (!(Character.isLetterOrDigit(c) || c == '_')) 
	                    break;
	                else
	                {
	                	lexeme += c;
	                }
	                c = nextChar();
                }                
                //Compare and
                if(lexeme.equals("and"))
                {
                	result = new Token(Token.AND,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                //Compare array
                else
                if(lexeme.equals("array"))
                {
                	result = new Token(Token.ARRAY,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                //compare begin
                else
                if(lexeme.equals("begin"))
                {
                	result = new Token(Token.BEGIN,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                //compare boolean
                else
                if(lexeme.equals("boolean"))
                {
                	result = new Token(Token.BOOLEAN,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                //Compare break
                else
                if(lexeme.equals("break"))
                {
                	result = new Token(Token.BREAK,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                //Compare const
                else
                if(lexeme.equals("const"))
                {
                	result = new Token(Token.CONST,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                //Compare continue
                else
                if(lexeme.equals("continue"))
                {
                	result = new Token(Token.CONTINUE,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                //Compare div
                else
                if(lexeme.equals("div"))
                {
                	result = new Token(Token.DIV,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                //Compare do
                else
                if(lexeme.equals("do"))
                {
                	result = new Token(Token.DO,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                //Compare downto
                else
                if(lexeme.equals("downto"))
                {
                	result = new Token(Token.DOWNTO,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                //Compare else
                else
                if(lexeme.equals("else"))
                {
                	result = new Token(Token.ELSE,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                //Compare end
                else
                if(lexeme.equals("end"))
                {
                	result = new Token(Token.END,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                //Compare for
                else
                if(lexeme.equals("for"))
                {
                	result = new Token(Token.FOR,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                //Compare function
                else
                if(lexeme.equals("function"))
                {
                	result = new Token(Token.FUNCTION,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                //Compare if
                else
                if(lexeme.equals("if"))
                {
                	result = new Token(Token.IF,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                //Compare mod
                else
                if(lexeme.equals("mod"))
                {
                	result = new Token(Token.MOD,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                //Compare not
                else
                if(lexeme.equals("not"))
                {
                	result = new Token(Token.NOT,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                //Compare of
                else
                if(lexeme.equals("of"))
                {
                	result = new Token(Token.OF,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                //Compare or
                else
                if(lexeme.equals("or"))
                {
                	result = new Token(Token.OR,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                //Compare procedure
                else
                if(lexeme.equals("procedure"))
                {
                	result = new Token(Token.PROCEDURE,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                //Compare program
                else
                if(lexeme.equals("program"))
                {
                	result = new Token(Token.PROGRAM,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                //Compare repeat
                else
                if(lexeme.equals("repeat"))
                {
                	result = new Token(Token.REPEAT,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                //Compare then
                else
                if(lexeme.equals("then"))
                {
                	result = new Token(Token.THEN,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                //Compare to
                else
                if(lexeme.equals("to"))
                {
                	result = new Token(Token.TO,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                //Compare until
                else
                if(lexeme.equals("until"))
                {
                	result = new Token(Token.UNTIL,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                //Compare var
                else
                if(lexeme.equals("var"))
                {
                	result = new Token(Token.VAR,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                //Compare while
                else
                if(lexeme.equals("while"))
                {
                	result = new Token(Token.WHILE,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                //Compare integer
                else
                if(lexeme.equals("integer"))
                {
                	result = new Token(Token.INTEGER,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                //Compare real
                else
                if(lexeme.equals("real"))
                {
                	result = new Token(Token.REAL,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                //Compare true
                else
                if(lexeme.equals("true"))
                {
                	result = new Token(Token.BOOLEANLITERAL,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                //Compare false
                else
                if(lexeme.equals("false"))
                {
                	result = new Token(Token.BOOLEANLITERAL,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
                	//read the "current read character" one more time
            		buff.goBackOneCharacter();
                	position.endToken();
                	return result;
                }
                else
                {  
               		result = new Token(Token.ID,lexeme,
                	new SourcePosition(position.charStart,position.charFinish-1,
                	position.lineStart,position.lineFinish));
            		buff.goBackOneCharacter();//read the "current read character" one more time
                	position.endToken();
                	return result;
                }
                //-------------- Xu ly van de Dot : dot, range, real
            case 8:
             	int stateDot = 0;
             	int tempCountDot = 0;
             	char tempDotc;             	
             	String tempDotStr = "";
             	boolean flagDot = false;
             	lexeme = "" + c;
             	while(true)
             	{
             		switch(stateDot)
             		{             		
             		case 0:
             			c = nextChar();
             			if(c == '.')
             			{
             				result = new Token(Token.RANGE,"..",position);
        					position.charFinish++;//go to next position
        					position.endToken();
	               			return result;
             			}
             			else
             			if(c == 'e' || c == 'E')
             			{
             				buff.goBackOneCharacter();
             				position.charFinish--;             				
             				tempDotc = buff.goAheadOneCharacter();
             				tempCountDot++;
             				tempDotStr += tempDotc;
             				stateDot = 2;
             				break;
             			}
             			else
             			if(Character.isDigit(c))
             			{
             				stateDot = 1;
             				lexeme += c;
             				flagDot = true;
             				break;
             			}
             			else
             			{
             				result = new Token(Token.DOT,".",
                	 			new SourcePosition(position.charStart,position.charFinish-1,
                				position.lineStart,position.lineFinish));
                			//read the "current read character" one more time
            				buff.goBackOneCharacter();
                			position.endToken();
                			return result;
             			}
             		case 1:
             			c = nextChar();
             			while(true)
             			{
             				if(Character.isDigit(c))
             				{
             					lexeme += c;
             					c = nextChar();
             				}
             				else
             				if(c == 'e' || c == 'E')
             				{
             					buff.goBackOneCharacter();
             					position.charFinish--;             				
             					tempDotc = buff.goAheadOneCharacter();
             					tempCountDot++;
             					tempDotStr += tempDotc;
             					stateDot = 2;
             					break;
             				}
             				else
             				{
             					result = new Token(Token.REALLITERAL,lexeme,
                	 				new SourcePosition(position.charStart,position.charFinish-1,
                					position.lineStart,position.lineFinish));
                				//read the "current read character" one more time
            					buff.goBackOneCharacter();
                				position.endToken();
                				return result;
             				}
             			}
             			break;
             		case 2:
             			tempDotc = buff.goAheadOneCharacter();
             			tempCountDot++;
             			tempDotStr += tempDotc;
             			if(tempDotc == '+' || tempDotc == '-')
             			{
             				stateDot = 3;
             			}
             			else
             			if(Character.isDigit(tempDotc))
             			{
             				position.charFinish += tempCountDot;
             				lexeme += tempDotStr;
             				stateDot = 4;
             			}
             			else
             			{
             				buff.goBackOneCharacter();
             				if(flagDot)
             				{
             					result = new Token(Token.REALLITERAL,lexeme,position);
        						position.charFinish++;//go to next position
        						position.endToken();
	               				return result;
             				}
             				result = new Token(Token.DOT,".",position);
        					position.charFinish++;//go to next position
        					position.endToken();
	               			return result;
             			}
             			break;
             		case 3:
             			tempDotc = buff.goAheadOneCharacter();
             			tempCountDot++;
             			tempDotStr += tempDotc;
             			if(Character.isDigit(tempDotc))
             			{
             				position.charFinish += tempCountDot;
             				lexeme += tempDotStr;
             				stateDot = 4;
             			}
             			else
             			{
             				buff.goBackOneCharacter();
             				if(flagDot)
             				{
             					result = new Token(Token.REALLITERAL,lexeme,position);
        						position.charFinish++;//go to next position
        						position.endToken();
	               				return result;
             				}
             				result = new Token(Token.DOT,".",position);
        					position.charFinish++;//go to next position
        					position.endToken();
	               			return result;
             			}
             			break;
             		case 4:
             			c = nextChar();
             			while(true)
             			{
             				if(!Character.isDigit(c))
             					break;
             				else
             				{
             					lexeme += c;
             					c = nextChar();
             				}
             			}
             			result = new Token(Token.REALLITERAL,lexeme,
                	 		new SourcePosition(position.charStart,position.charFinish-1,
                			position.lineStart,position.lineFinish));
                		//read the "current read character" one more time
            			buff.goBackOneCharacter();
                		position.endToken();
                		return result;           		
             	}               		
    		}
                //--------------------------------------------------                 
    		}
    	}
    }  
}

class ScannerBuffer{
    private static final char EOF = '\u0000';
	BufferedReader bufferedReader;
	ScannerBuffer(String fileName){
		try{
	        File file = new File(fileName);
	        FileReader reader = new FileReader(file);
	        bufferedReader = new BufferedReader(reader);
	        bufferedReader.mark(128);//mark the beginning of input buffer
	    }
		catch (Exception e)
        {}
	}
    public char nextChar() {
    	char result = EOF;
    	try{
	    	int r;
    		bufferedReader.mark(128);	    		
	    	if ((r = bufferedReader.read())!=-1)
	    	{
	    		result =  (char)r;
	    	}
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }
    public void goBackOneCharacter(){
        reset();
    }
    public void reset(){
        try{
        	bufferedReader.reset();
        }
        catch (Exception e){
        }
    }
    public char goAheadOneCharacter(){
    	char result = EOF;
        try{
        	int r;
	    	if ((r = bufferedReader.read())!=-1)
	    	{
	    		result =  (char)r;
	    	}
        }
        catch (Exception e){
        }    
        return result;
    }
}
